package com.demo;
import org.openjdk.jol.info.ClassLayout;
public class ClassInstanceMemory {
    static class Demo{
        private int a = 10;
        private double b = 1.0D;
    }

    static class Demo2{
        private double a = 10;
        private double b = 1.0D;
    }

    static class Demo3{
        private double a = 10;
        private double b = 1.0D;
        private int c = 2;
    }
    static class Demo4{
        private double a = 10;
        private double b = 1.0D;
        private int c = 2;
        private int d = 3;
    }

    static class Demo5{
        private double a = 10;
        private double b = 1.0D;
        private int c = 2;
        private int d = 3;
        private int[] e = new int[]{1,2,3,4,5,6,7,8,9,0};
        private String f = new String("hello world");
        private String[] g = new String[]{"abc","def"};
        private boolean h = true;
    }

    static class Demo6{
        private boolean a = true;
        private boolean b = false;
        private boolean c = true;
        private boolean d = true;
        private boolean e = true;
    }
    public static void main(String[] args) {
        /*Object object = new Object();
        ClassLayout layout = ClassLayout.parseInstance(object);
        System.out.println(layout.toPrintable());*/

//        int[] intArray = new int[256*256*256*16*4];
        int[] intArray = new int[4];
        ClassLayout layout = ClassLayout.parseInstance(intArray);
        System.out.println(layout.toPrintable());

        /*Demo6 object = new Demo6();
        ClassLayout layout = ClassLayout.parseInstance(object);
        System.out.println(layout.toPrintable());*/

        /*System.out.println(ClassLayout.parseClass(Long.class).toPrintable());
        System.out.println(ClassLayout.parseInstance(123456789L).toPrintable());*/

        /*System.out.println(ClassLayout.parseClass(Integer.class).toPrintable());
        System.out.println(ClassLayout.parseInstance(123).toPrintable());*/

    }
}
/*
32位操作系统每次可以处理32个比特位，也就是4个字节。64位处理系统一次可以处理64个比特位，也就是8个字节。
数据在64位jvm中存储较之32位jvm需要对数据位进行对齐补白,所有数据都必须是8个字节的整倍数存储，可以两个int补齐一个8位
如可以1个boolean+7个byte进行补位

-XX:+UseCompressedOops
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           e5 01 00 f8 (11100101 00000001 00000000 11111000) (-134217243)
     12     4        (loss due to the next object alignment)
Instance size: 16 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total
-XX:-UseCompressedOops
 OFFSET  SIZE   TYPE DESCRIPTION                               VALUE
      0     4        (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4        (object header)                           00 1c cc 20 (00000000 00011100 11001100 00100000) (550247424)
     12     4        (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
Instance size: 16 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

来看一下使用demo的例子：
 OFFSET  SIZE     TYPE DESCRIPTION                               VALUE
      0     4          (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4          (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4          (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4      int Demo.a                                    10
     16     8   double Demo.b                                    1.0
Instance size: 24 bytes
markword占用8字节，klass pointer占用4字节，而对象的第一个属性是int类型，刚好占用4字节，跟klass pointer刚好8字节，所以不需要补位
而第二个属性是double类型，刚好占用8字节，也不需要补位

对比Demo2：
 OFFSET  SIZE     TYPE DESCRIPTION                               VALUE
      0     4          (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4          (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4          (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4          (alignment/padding gap)
     16     8   double Demo2.a                                   10.0
     24     8   double Demo2.b                                   1.0
Instance size: 32 bytes
可以看到由于第一个属性是double类型，本身占用8字节，无法与header中的klass pointer共同组成8字节，所以klass pointer就需要补位了
可以以此来观察类设计的是否合理

对比Demo3：
 OFFSET  SIZE     TYPE DESCRIPTION                               VALUE
      0     4          (object header)                           01 00 00 00 (00000001 00000000 00000000 00000000) (1)
      4     4          (object header)                           00 00 00 00 (00000000 00000000 00000000 00000000) (0)
      8     4          (object header)                           43 c1 00 f8 (01000011 11000001 00000000 11111000) (-134168253)
     12     4      int Demo3.c                                   2
     16     8   double Demo3.a                                   10.0
     24     8   double Demo3.b                                   1.0
Instance size: 32 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total
jvm会进行优化，并不一定按照定义顺序存储



在64位jvm系统中：
在对象头中，开启指针压缩，markword共计8字节，klass pointer被压缩成4个字节，补齐4个字节，共计16个字节
不开启指针压缩，marword共计8字节，klass pointer占用8字节，满足8的背书，不需要补位，共计16个字节

那为啥开启指针压缩后，指针被压缩成4字节，还要进行补位存储这样的麻烦操作？
在64位操作系统中，8字节的指针浪费空间，所以java1.6后默认开启指针压缩，将8字节指针压缩到4字节来保存
4字节的指针，既256^4,只能表示4GB的内存，java进程开启指针压缩难道只能使用4GB的内存？显然不是。
java中的4字节指针，并不是对象的真实指针（内存上的指针），而是一个偏移量。每个指针指向一段内存，
这段内存占用8字节=64位，所以jvm保存数据，无论是什么类型，都要保证存储的是8字节的整数倍
所以java通过使用指针压缩技术，可以使用4字节的指针，寻址32GB的内存。4GB*(2^3)=32GB

当java的占用物理内存超过32GB的时候，可能会打破指针压缩。
当jvm的堆内存在4-32GB的时候，开启指针压缩
当jvm的堆内存在4GB以下时，不会开启指针压缩，jvm会自动去除指针的高32位，以此来减少开启指针压缩带来的性能损耗。
所以微服务拆分可以通过4GB作为一个度量单位，因为毕竟压缩指针是一个编码解码的过程，还是对性能有损耗的

哪些信息会被压缩？
    对象的全局静态变量(即类属性)
    对象头信息:64位平台下，原生对象头大小为16字节，压缩后为12字节
    对象的引用类型:64位平台下，引用类型本身大小为8字节，压缩后为4字节
    对象数组类型:64位平台下，数组类型本身大小为24字节，压缩后16字节
哪些信息不会被压缩？
    指向非Heap的对象指针
    局部变量、传参、返回值、NULL指针

是否有办法，将指针压缩提高，比如，指针舍弃的不是3位，而是4位，一个指针寻址2^4=16个字节，则4GB*16=64GB，如果能，jvm将
可以在64GB的内存上开启指针压缩。
 */